(require '[fx-clj.internal.util])
(fx-clj.internal.util/ns-start-loading 'fx-clj.core.convert)

(ns ^:no-doc fx-clj.core.convert
  (:require
    [fx-clj.core.extensibility :refer [convert-arg]]
    [fx-clj.util :as util]
    [freactive.core :as f]
    [clojure.core.async :refer [put!]]
    [org.tobereplaced.lettercase :as lettercase])
  (:import (fx_clj.binding ReactiveAtomObservable)
           (java.lang.reflect Method)
           (java.util Collection)))

;; <<----------------------
(fx-clj.internal.util/ns-libs-loaded 'fx-clj.core.convert)
;; ---------------------->>

(defn- convert-cell-value-factory [v {:keys [method]}]
  (let [method-name (.getName ^Method method)]
    (when (= method-name "cellValueFactoryProperty")
      (util/cell-value-factory v))))

; ==============================================

(defmethod convert-arg :default [_ v _] v)

(defmethod convert-arg [javafx.event.EventHandler clojure.lang.IFn] [_ f _]
  (util/event-handler* f))

(defmethod convert-arg [javafx.event.EventHandler clojure.core.async.impl.channels.ManyToManyChannel] [_ ch _]
  (util/event-handler [e] (put! ch e)))

(defmethod convert-arg [javafx.util.Callback clojure.lang.IFn] [_ f _]
  (util/callback* f))

;;========== cell value factory ==========
(defmethod convert-arg [javafx.util.Callback clojure.lang.Named] [_ v opts]
  (or
    (convert-cell-value-factory v opts)
    v))

(defmethod convert-arg [javafx.util.Callback String] [_ v opts]
  (or
    (convert-cell-value-factory v opts)
    v))

(prefer-method convert-arg
               [javafx.util.Callback clojure.lang.Named]
               [javafx.util.Callback clojure.lang.IFn])
;; =======================================

(defmethod convert-arg [Enum clojure.lang.Keyword] [enum kw _]
  (Enum/valueOf enum (lettercase/upper-underscore-name kw)))

(defmethod convert-arg [String clojure.lang.Named] [_ v _]
  (name v))

(defmethod convert-arg [javafx.collections.ObservableList clojure.lang.Sequential]
  [_ v {:keys [element-type] :or {element-type Object}}]
  #_(javafx.collections.FXCollections/observableList (for [x v] (convert-arg element-type x nil)))
  (javafx.collections.FXCollections/observableArrayList ^Collection (for [x v] (convert-arg element-type x nil))))

(defmethod convert-arg [javafx.collections.ObservableList clojure.lang.IDeref]
  [t v opts]
  ;(println "convert IDeref to ObservableList" t v)
  (f/rx (convert-arg t @v opts)))

(prefer-method convert-arg
               [javafx.collections.ObservableList clojure.lang.Sequential]
               [Object clojure.lang.PersistentVector])

(defmethod convert-arg [javafx.scene.Node javax.swing.JComponent] [nt jc _]
  (doto (javafx.embed.swing.SwingNode.)
    (.setContent jc)))

(defmethod convert-arg [javafx.beans.property.Property freactive.IReactiveAtom] [_ a _]
  (ReactiveAtomObservable. a))



(fx-clj.internal.util/ns-loaded 'fx-clj.core.convert)